﻿/*
 * InstanceHandler
 * 
 * Help manage service object instane
 * 
 * Author: snowdreamist
 * Date: 2011/12/7
 * 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BitTorrentSharp.KRPC.Handler
{
    public abstract class ServiceInstanceHandler
    {
        public static ServiceInstanceHandler CreateHandler(Type serviceType,ServiceInstanceMode instanceMode, Type serviceFactoryType)
        {
            if (serviceType == null)
                throw new ArgumentNullException("serviceType");

            switch(instanceMode)
            {
                case ServiceInstanceMode.Singleton:
                    return new SingletonServiceInstanceHandler(serviceType, instanceMode, serviceFactoryType);

                default:
                    throw new KRPCActiveException("Unknown service instance mode");
            }
        }

        protected ServiceInstanceHandler(Type serviceType,ServiceInstanceMode instanceMode, Type serviceFactoryType)
        {
            this.InstanceMode = instanceMode;

            if (serviceFactoryType == null)
            {
                this.Factory = new DefaultServiceInstanceFactory(serviceType);
            }
            else
            {
                this.Factory = this.CreateFactory(serviceFactoryType);
                if (this.Factory == null)
                    throw new KRPCActiveException("Failed to create service instance factory.");
            }
        }

        #region properties
        /// <summary>
        /// Service instance mode
        /// </summary>
        public ServiceInstanceMode InstanceMode { get; private set; }
        /// <summary>
        /// Service instance factory
        /// </summary>
        public IServiceInstanceFactory Factory { get; private set; }

        #endregion

        /// <summary>
        /// Get service instance
        /// </summary>
        /// <returns></returns>
        public object GetInstance()
        {
            return this.InternalGetInstance(this.Factory);
        }
        /// <summary>
        /// Internal implementation
        /// </summary>
        internal protected abstract object InternalGetInstance(IServiceInstanceFactory factory);

        #region private

        private IServiceInstanceFactory CreateFactory(Type factoryType)
        {
            return Activator.CreateInstance(factoryType) as IServiceInstanceFactory;
        }
        #endregion
    }

    public class SingletonServiceInstanceHandler : ServiceInstanceHandler
    {
        internal SingletonServiceInstanceHandler(Type serviceType, ServiceInstanceMode instanceMode, Type serviceFactoryType)
            : base(serviceType, instanceMode, serviceFactoryType) { }

        protected internal override object InternalGetInstance(IServiceInstanceFactory factory)
        {
            if(this._instance == null)
                lock (this._syncRoot)
                {
                    if (this._instance == null)
                        this._instance = factory.CreateServiceInstance();
                }

            return this._instance;
        }

        #region private

        private readonly object _syncRoot = new object();

        private volatile object _instance = null;

        #endregion
    }

}
